package zhibi.wechat.mp.controller;

import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import zhibi.commons.exception.MessageException;
import zhibi.frame.context.Constant;
import zhibi.utils.security.SecurityUtil;
import zhibi.wechat.mp.domain.User;
import zhibi.wechat.mp.extra.base.BaseController;
import zhibi.wechat.mp.extra.util.Digests;
import zhibi.wechat.mp.extra.util.Encodes;
import zhibi.wechat.mp.service.UserService;

import static zhibi.wechat.mp.extra.context.BaseConfig.REQUEST_PREFIX;

@Controller
@RequestMapping(REQUEST_PREFIX)
public class WxMpController extends BaseController {

    @Autowired
    private WxMpService wxService;
    @Autowired
    private WxMpMessageRouter router;
    @Autowired
    private UserService userService;

    @RequestMapping("index")
    public String index() {
        return VIEW_PREFIX + "index";
    }

    @RequestMapping("welcome")
    public String welcome() {
        return VIEW_PREFIX + "welcome";
    }

    /**
     * 校验token
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @param echostr
     * @return
     */
    @GetMapping(value = "auth", produces = "text/plain;charset=utf-8")
    @ResponseBody
    public String authGet(
            @RequestParam(name = "signature",
                    required = false) String signature,
            @RequestParam(name = "timestamp",
                    required = false) String timestamp,
            @RequestParam(name = "nonce", required = false) String nonce,
            @RequestParam(name = "echostr", required = false) String echostr) {
        this.logger.info("\n接收到来自微信服务器的认证消息：[{}, {}, {}, {}]", signature,
                timestamp, nonce, echostr);
        if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
            throw new IllegalArgumentException("请求参数非法，请核实!");
        }
        if (this.wxService.checkSignature(timestamp, nonce, signature)) {
            return echostr;
        }
        return "非法请求";
    }

    /**
     * 接收微信消息
     *
     * @param requestBody
     * @param signature
     * @param timestamp
     * @param nonce
     * @param encType
     * @param msgSignature
     * @return
     */
    @PostMapping(value = "auth", produces = "application/xml; charset=UTF-8")
    @ResponseBody
    public String post(@RequestBody String requestBody,
                       @RequestParam("signature") String signature,
                       @RequestParam("timestamp") String timestamp,
                       @RequestParam("nonce") String nonce,
                       @RequestParam(name = "encrypt_type",
                               required = false) String encType,
                       @RequestParam(name = "msg_signature",
                               required = false) String msgSignature) {
        this.logger.info("接收微信请求：[signature=[{}], encType=[{}], msgSignature=[{}],"
                        + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
                signature, encType, msgSignature, timestamp, nonce, requestBody);
        if (!this.wxService.checkSignature(timestamp, nonce, signature)) {
            throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
        }
        String out = null;
        if (encType == null) {
            // 明文传输的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
            WxMpXmlOutMessage outMessage = this.route(inMessage);
            if (outMessage == null) {
                return "";
            }
            out = outMessage.toXml();
        } else if ("aes".equals(encType)) {
            // aes加密的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(
                    requestBody, this.wxService.getWxMpConfigStorage(), timestamp,
                    nonce, msgSignature);
            this.logger.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
            WxMpXmlOutMessage outMessage = this.route(inMessage);
            if (outMessage == null) {
                return "";
            }
            out = outMessage
                    .toEncryptedXml(this.wxService.getWxMpConfigStorage());
        }

        this.logger.debug("\n组装回复信息：{}", out);

        return out;
    }

    /**
     * 微信消息处理
     *
     * @param message
     * @return
     */
    private WxMpXmlOutMessage route(WxMpXmlMessage message) {
        try {
            return this.router.route(message);
        } catch (Exception e) {
            this.logger.error(e.getMessage(), e);
        }
        return null;
    }


    public static final int HASH_INTERATIONS = 1024;

    /**
     * 验证密码
     *
     * @param plainPassword 明文密码
     * @param password      密文密码
     * @return 验证成功返回true
     */
    private boolean validatePassword(String plainPassword, String password) {
        byte[] salt = Encodes.decodeHex(password.substring(0, 16));
        byte[] hashPassword = Digests.sha1(plainPassword.getBytes(), salt, HASH_INTERATIONS);
        return password.equals(Encodes.encodeHex(salt) + Encodes.encodeHex(hashPassword));
    }

    @GetMapping("login")
    public String login() {
        return VIEW_PREFIX + "login";
    }

    @PostMapping("login")
    public String login(String username, String password) {
        User user = userService.selectByPrimaryKey(username);
        if (null == user || !user.getNickname().equals(SecurityUtil.MD5(password).toUpperCase()))
            throw new MessageException("用户名或密码错误");
        logger.info("【 登 录 】 用户:{}  ", user.getOpenId());
        session.setAttribute(Constant.SESSION.ADMIN, user);
        return redirect("index");
    }

    @GetMapping("logout")
    public String logout() {
        session.removeAttribute(Constant.SESSION.ADMIN);
        return redirect("index");
    }

}
